/**
 * @program: malll
 * @description:
 * @author: Mr.Xu
 * @create: 2020-12-30 11:01
 **/

package com.bobo.mall.product.web;

import com.bobo.mall.product.entity.CategoryEntity;
import com.bobo.mall.product.service.CategoryService;
import com.bobo.mall.product.vo.Catelog2Vo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Controller
@Slf4j
public class IndexController {

    @Autowired
    CategoryService categoryService;
    @Autowired
    RedissonClient redisson;
    @Autowired
    StringRedisTemplate redisTemplate;

    @GetMapping({"/","/index.html"})
    public String indexPage(Model model){

        // 查出所有商品的一级目录
        List<CategoryEntity> categoryEntities = categoryService.getLever1Categorys();
        model.addAttribute("catagorys",categoryEntities);
        return "index";
    }

    // index/catalog.json
    @GetMapping("/index/catalog.json")
    @ResponseBody
    public Map<String, List<Catelog2Vo>> getCatalogJson(){
        Map<String, List<Catelog2Vo>> catalogJson = categoryService.getCatalogJson();
        return catalogJson;
    }

    @ResponseBody
    @GetMapping("/hello")
    public String hello() throws InterruptedException {
        RLock lock = null;
        try{
            // 1、获取一把锁，只要锁的名字一样，就是同一把锁
            lock = redisson.getLock("myLock");
            // 2、加锁
            lock.lock(); // 阻塞式等待是，默认加锁的时间是 30S，
            //lock.lock(10, TimeUnit.SECONDS); // 如果设置过期时间，时间一定大于业务执行时间，不然会报异常
            // ① 锁的自动续期（看门狗），如果业务超长，运行期间自动给锁续上新的30S，不用担心业务时间过长，所自动过期被删掉
            // ② 加锁的业务只要运行完成，就不会给当前锁续期，及时不手动解锁，锁默认在 30S 以后自动删除
            System.out.println("加锁成功，执行相应的业务逻辑"+Thread.currentThread().getId());
            Thread.sleep(3000);
        }finally {
            // 3、解锁，假设解锁代码没有运行，redisson 会不会出现死锁
            System.out.println("释放锁。。。。"+ Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }

    @GetMapping("/write")
    @ResponseBody
    public String writeValue(){
        String s = UUID.randomUUID().toString();
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        RLock rLock = lock.writeLock();
        try {
            rLock.lock();
            Thread.sleep(3000);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();
        }
        return s;
    }

    @GetMapping("/read")
    @ResponseBody
    public String readValue(){
        String readValue = "";
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        RLock rLock = lock.readLock();
        try{
            rLock.lock();
            readValue = redisTemplate.opsForValue().get("writeValue");
        }finally {
            rLock.unlock();
        }

        return readValue;
    }

    @GetMapping("/lockdoor")
    @ResponseBody
    /**
     *     CountDownLatch
     */
    public String lockDoor() throws InterruptedException {
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.trySetCount(5);
        door.await();   // 等待锁都完成
        return "放假开始锁门了";
    }

    @GetMapping("/gogo/{id}")
    @ResponseBody
    public String gogo(@PathVariable("id") Long id){
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.countDown(); // 计数减一
        return id + "号学生放学回家了";
    }

    @GetMapping("/pack")
    @ResponseBody
    public String pack(){
        RSemaphore park = redisson.getSemaphore("park");
        park.trySetPermits(2);
        return "车位满了，你可以离开了";
    }
    @GetMapping("/go")
    @ResponseBody
    public String go() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("park");
       // park.acquire();
        boolean b = park.tryAcquire();
        return "我搞到一辆车"+b;
    }

}